﻿using HDSmartCommunity.BUS;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Timer = System.Timers.Timer;

namespace HDSmartCommunity.DevicePlatform
{
    public class DYDeviceSerialData
    {
        public SerialPort myS0SerialPort = new SerialPort();
        private Timer SerialPortRecvTimerS0;
        private static int byteLength = 40960;
        public byte[] byteSerialPortRecvS0 = new byte[byteLength];
        public event EventHandler<SerialPort485_1RecvEventArgs> ReceivedDataEventS0;
        private static int pSerialPortRecv_S0 = 0;
        public void OpenS0SerialPort(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            try
            {
                SetS0SerialPortConfig(portName, baudRate, parity, dataBits, stopBits);
                myS0SerialPort.Open();
                LogHelper.Log("串口" + portName + "打开成功");
            }
            catch (Exception e)
            {
                LogHelper.Log("串口" + portName + "打开异常" + e.ToString());
            }
        }

        private void SetS0SerialPortConfig(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                portName = $"/dev/{portName}";
            }
            // 串口 参数设置
            myS0SerialPort.PortName = portName;
            myS0SerialPort.BaudRate = baudRate;
            switch (parity)
            {
                case 0:
                default:
                    myS0SerialPort.Parity = Parity.None;
                    break;
                case 1:
                    myS0SerialPort.Parity = Parity.Odd;
                    break;
                case 2:
                    myS0SerialPort.Parity = Parity.Even;
                    break;
                case 3:
                    myS0SerialPort.Parity = Parity.Mark;
                    break;
                case 4:
                    myS0SerialPort.Parity = Parity.Space;
                    break;
            }
            myS0SerialPort.DataBits = ((4 < dataBits) && (dataBits < 9)) ? dataBits : 8;
            switch (stopBits)
            {
                case 0:
                    myS0SerialPort.StopBits = StopBits.None;
                    break;
                case 1:
                default:
                    myS0SerialPort.StopBits = StopBits.One;
                    break;
                case 2:
                    myS0SerialPort.StopBits = StopBits.OnePointFive;
                    break;
                case 3:
                    myS0SerialPort.StopBits = StopBits.Two;
                    break;
            }
            //my485SerialPort_1.ReadTimeout = 200;
            myS0SerialPort.RtsEnable = true;
            myS0SerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived_ttyS0);

            // 串口 接收数据处理定时器 参数设置
            SerialPortRecvTimerS0 = new System.Timers.Timer();
            SerialPortRecvTimerS0.Interval = 100;
            SerialPortRecvTimerS0.AutoReset = false;
            SerialPortRecvTimerS0.Elapsed += new ElapsedEventHandler(SPRecvTimer_Tick_ttyS0_1);
        }

        public class SerialPort485_1RecvEventArgs : EventArgs
        {
            /// <summary>
            /// 广播 收到的串口数据
            /// </summary>
            public readonly byte[] RecvData_485_1 = new byte[byteLength];

            /// <summary>
            /// 收到数据 的 长度
            /// </summary>
            public readonly int RecvDataLength_485_1;

            /// <summary>
            /// 将 收到的数据 转化成 待广播的数据
            /// </summary>
            public SerialPort485_1RecvEventArgs(byte[] recvData, int recvDataLength)
            {
                recvData.CopyTo(RecvData_485_1, 0);
                RecvDataLength_485_1 = recvDataLength;
            }
        }

        private void SPRecvTimer_Tick_ttyS0_1(object sender, EventArgs e)
        {
            byte[] TemporaryData = new byte[byteLength];
            int TemporaryDataLength = 0;

            if (ReceivedDataEventS0 != null)
            {
                byteSerialPortRecvS0.CopyTo(TemporaryData, 0);
                TemporaryDataLength = pSerialPortRecv_S0;

                ReceivedDataEventS0.Invoke(this, new SerialPort485_1RecvEventArgs(TemporaryData, TemporaryDataLength));
                // 数据处理完后，将指针指向数据头，等待接收新的数据
                pSerialPortRecv_S0 = 0;
            }
        }

        private void DataReceived_ttyS0(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPortRecvTimerS0.Stop();
            try
            {
                byte[] ReadBuf = new byte[myS0SerialPort.BytesToRead];
                if (pSerialPortRecv_S0 > byteLength - ReadBuf.Length)
                {
                    pSerialPortRecv_S0 = 0;
                }
                myS0SerialPort.Read(ReadBuf, 0, ReadBuf.Length);
                ReadBuf.CopyTo(byteSerialPortRecvS0, pSerialPortRecv_S0);
                pSerialPortRecv_S0 += ReadBuf.Length;
                for (int i = 0; i < byteSerialPortRecvS0.Length; i++)
                {
                    //01 03 06 0E D9 0E DA 0E E4 1A B0
                    if (byteSerialPortRecvS0[i] == 0x01 && byteSerialPortRecvS0[i + 1] == 0x03 && byteSerialPortRecvS0[i + 2] == 0x06)
                    {
                        int data_count = 9;
                        byte[] databuffer = new byte[data_count];
                        for (int k = 0; k < data_count; k++)
                        {
                            databuffer[k] = byteSerialPortRecvS0[i + k];
                        }

                        byte[] data_crc = Crc(databuffer);
                        if (data_crc[0] == byteSerialPortRecvS0[i + 10] && data_crc[1] == byteSerialPortRecvS0[i + 9])
                        {
                            byte[] data = new byte[data_count + 2];
                            for (int m = 0; m < data_count + 2; m++)
                            {
                                data[m] = byteSerialPortRecvS0[m + i];
                            }
                            Array.Clear(byteSerialPortRecvS0, i, data.Length);
                            byte[] ua = new byte[2];
                            ua[0] = data[3];
                            ua[1] = data[4];
                            byte[] ub = new byte[2];
                            ub[0] = data[5];
                            ub[1] = data[6];
                            byte[] uc = new byte[2];
                            uc[0] = data[7];
                            uc[1] = data[8];

                            double a = Math.Round(intStringToDouble(ua) * 0.1, 1);
                            double b = Math.Round(intStringToDouble(ub) * 0.1, 1);
                            double c = Math.Round(intStringToDouble(uc) * 0.1, 1);
                            string message = a + "," + b + "," + c;
                            DYLogHelper.Log(message, "01");
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
            SerialPortRecvTimerS0.Start();
        }

        public double intStringToDouble(byte[] data)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sb.Append(data[i].ToString("X2"));
            }
            return Convert.ToInt32(sb.ToString(), 16);
        }

        #region CRC校验
        public byte[] Crc(byte[] buffer, int start = 0, int len = 0)
        {
            if (buffer == null || buffer.Length == 0) return null;
            if (start < 0) return null;
            if (len == 0) len = buffer.Length - start;
            int length = start + len;
            if (length > buffer.Length) return null;
            ushort crc = 0xFFFF;// Initial value
            for (int i = start; i < length; i++)
            {
                crc ^= buffer[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 1) > 0)
                        crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005
                    else
                        crc = (ushort)(crc >> 1);
                }
            }
            byte[] ret = BitConverter.GetBytes(crc);
            Array.Reverse(ret);
            return ret;
        }
        #endregion

        public SerialPort myS1SerialPort = new SerialPort();
        private Timer SerialPortRecvTimerS1;
        private static int byteLength2 = 40960;
        public byte[] byteSerialPortRecvS1 = new byte[byteLength2];
        public event EventHandler<SerialPort485_2RecvEventArgs> ReceivedDataEventS1;
        private static int pSerialPortRecv_S1 = 0;

        public void OpenS1SerialPort(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            try
            {
                SetS1SerialPortConfig(portName, baudRate, parity, dataBits, stopBits);
                myS1SerialPort.Open();
                LogHelper.Log("串口" + portName + "打开成功");
            }
            catch (Exception e)
            {
                LogHelper.Log("串口" + portName + "打开异常" + e.ToString());
            }
        }

        private void SetS1SerialPortConfig(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                portName = $"/dev/{portName}";
            }
            // 串口 参数设置
            myS1SerialPort.PortName = portName;
            myS1SerialPort.BaudRate = baudRate;
            switch (parity)
            {
                case 0:
                default:
                    myS1SerialPort.Parity = Parity.None;
                    break;
                case 1:
                    myS1SerialPort.Parity = Parity.Odd;
                    break;
                case 2:
                    myS1SerialPort.Parity = Parity.Even;
                    break;
                case 3:
                    myS1SerialPort.Parity = Parity.Mark;
                    break;
                case 4:
                    myS1SerialPort.Parity = Parity.Space;
                    break;
            }
            myS1SerialPort.DataBits = ((4 < dataBits) && (dataBits < 9)) ? dataBits : 8;
            switch (stopBits)
            {
                case 0:
                    myS1SerialPort.StopBits = StopBits.None;
                    break;
                case 1:
                default:
                    myS1SerialPort.StopBits = StopBits.One;
                    break;
                case 2:
                    myS1SerialPort.StopBits = StopBits.OnePointFive;
                    break;
                case 3:
                    myS1SerialPort.StopBits = StopBits.Two;
                    break;
            }
            //my485SerialPort_1.ReadTimeout = 200;
            myS1SerialPort.RtsEnable = true;
            myS1SerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived_ttyS1);

            // 串口 接收数据处理定时器 参数设置
            SerialPortRecvTimerS1 = new System.Timers.Timer();
            SerialPortRecvTimerS1.Interval = 100;
            SerialPortRecvTimerS1.AutoReset = false;
            SerialPortRecvTimerS1.Elapsed += new ElapsedEventHandler(SPRecvTimer_Tick_ttyS1);
        }

        public class SerialPort485_2RecvEventArgs : EventArgs
        {
            /// <summary>
            /// 广播 收到的串口数据
            /// </summary>
            public readonly byte[] RecvData_485_2 = new byte[byteLength2];

            /// <summary>
            /// 收到数据 的 长度
            /// </summary>
            public readonly int RecvDataLength_485_2;

            /// <summary>
            /// 将 收到的数据 转化成 待广播的数据
            /// </summary>
            public SerialPort485_2RecvEventArgs(byte[] recvData, int recvDataLength)
            {
                recvData.CopyTo(RecvData_485_2, 0);
                RecvDataLength_485_2 = recvDataLength;
            }
        }
        private void SPRecvTimer_Tick_ttyS1(object sender, EventArgs e)
        {
            byte[] TemporaryData = new byte[byteLength2];
            int TemporaryDataLength = 0;

            if (ReceivedDataEventS1 != null)
            {
                byteSerialPortRecvS1.CopyTo(TemporaryData, 0);
                TemporaryDataLength = pSerialPortRecv_S1;

                ReceivedDataEventS1.Invoke(this, new SerialPort485_2RecvEventArgs(TemporaryData, TemporaryDataLength));
                // 数据处理完后，将指针指向数据头，等待接收新的数据
                pSerialPortRecv_S1 = 0;
            }
        }

        private void DataReceived_ttyS1(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPortRecvTimerS1.Stop();
            try
            {
                byte[] ReadBuf = new byte[myS1SerialPort.BytesToRead];
                if (pSerialPortRecv_S1 > byteLength2 - ReadBuf.Length)
                {
                    pSerialPortRecv_S1 = 0;
                }
                myS1SerialPort.Read(ReadBuf, 0, ReadBuf.Length);
                ReadBuf.CopyTo(byteSerialPortRecvS1, pSerialPortRecv_S1);
                pSerialPortRecv_S1 += ReadBuf.Length;
                for (int i = 0; i < byteSerialPortRecvS1.Length; i++)
                {
                    if (byteSerialPortRecvS1[i] == 0x02 && byteSerialPortRecvS1[i + 1] == 0x03 && byteSerialPortRecvS1[i + 2] == 0x06)
                    {
                        int data_count = 9;
                        byte[] databuffer = new byte[data_count];
                        for (int k = 0; k < data_count; k++)
                        {
                            databuffer[k] = byteSerialPortRecvS1[i + k];
                        }

                        byte[] data_crc = Crc(databuffer);
                        if (data_crc[0] == byteSerialPortRecvS1[i + 10] && data_crc[1] == byteSerialPortRecvS1[i + 9])
                        {
                            byte[] data = new byte[data_count + 2];
                            for (int m = 0; m < data_count + 2; m++)
                            {
                                data[m] = byteSerialPortRecvS1[m + i];
                            }
                            Array.Clear(byteSerialPortRecvS1, i, data.Length);
                            byte[] ua = new byte[2];
                            ua[0] = data[3];
                            ua[1] = data[4];
                            byte[] ub = new byte[2];
                            ub[0] = data[5];
                            ub[1] = data[6];
                            byte[] uc = new byte[2];
                            uc[0] = data[7];
                            uc[1] = data[8];

                            double a = Math.Round(intStringToDouble(ua) * 0.1, 1);
                            double b = Math.Round(intStringToDouble(ub) * 0.1, 1);
                            double c = Math.Round(intStringToDouble(uc) * 0.1, 1);
                            string message = a + "," + b + "," + c;
                            DYLogHelper.Log(message, "02");
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
            SerialPortRecvTimerS1.Start();
        }

        public static CancellationTokenSource cmd_tokenSource = new CancellationTokenSource();
        public CancellationToken cmd_token = cmd_tokenSource.Token;
        public ManualResetEvent cmd_resetEvent = new ManualResetEvent(true);

        public static CancellationTokenSource cmd_tokenSource_2 = new CancellationTokenSource();
        public CancellationToken cmd_token_2 = cmd_tokenSource_2.Token;
        public ManualResetEvent cmd_resetEvent_2 = new ManualResetEvent(true);

        public void QueryElevatorStatus()
        {
            try
            {
                Task task = new Task(async () =>
                {
                    if (cmd_token.IsCancellationRequested)
                    {
                        return;
                    }
                    cmd_resetEvent.WaitOne();
                    //do something
                    DateTime startTime = DateTime.Now;
                    string cmd1 = "01 03 00 00 00 03 05 CB";
                    string cmd2 = "02 03 00 00 00 03 05 F8";
                    while (true)
                    {
                        try
                        {
                            TimeSpan secondSpan = new TimeSpan(DateTime.Now.Ticks - startTime.Ticks);
                            if (secondSpan.TotalMilliseconds > 200)
                            {
                                QueryttyS0_Status(cmd1);
                                QueryttyS1_Status(cmd2);
                                startTime = DateTime.Now;
                            }
                        }
                        catch
                        {
                        }
                    }
                }, cmd_token);
                task.Start();
            }
            catch (Exception e)
            {
            }
        }

        public void QueryttyS0_Status(string cmd)
        {
            try
            {
                myS0SerialPort.Write(ToBytesSendDate(cmd), 0, ToBytesSendDate(cmd).Length);
            }
            catch (Exception ex)
            {
                LogHelper.Log(ex.ToString());
                return;
            }
        }

        public byte[] ToBytesSendDate(string str)
        {
            List<byte> result = new List<byte>();
            if (str.Contains(" "))
            {
                string[] strs = str.Trim().Split(' ');
                foreach (string s in strs)
                {
                    result.Add(Convert.ToByte(s.Trim(), 16));
                }
            }
            else
            {
                result.Add(Convert.ToByte(str, 16));
            }
            return result.ToArray();
        }

        public void QueryttyS1_Status(string cmd)
        {
            try
            {
                myS1SerialPort.Write(ToBytesSendDate(cmd), 0, ToBytesSendDate(cmd).Length);
            }
            catch (Exception ex)
            {
                LogHelper.Log("命令" + cmd + "发送失败" + ex.ToString());
                return;
            }
        }
    }
}
